home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / mac / macdraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-13  |  26.7 KB  |  946 lines  |  [TEXT/KAHL]

  1. /* Low-level drawing for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. #include "macconq.h"
  11.  
  12. PolyHandle polygons[NUMPOWERS];
  13. int lastpolyx[NUMPOWERS], lastpolyy[NUMPOWERS];
  14.  
  15. RgnHandle cellrgns[NUMPOWERS];
  16. int lastcellrgnx[NUMPOWERS], lastcellrgny[NUMPOWERS];
  17. RgnHandle gridcellrgns[NUMPOWERS];
  18. int lastgridcellrgnx[NUMPOWERS], lastgridcellrgny[NUMPOWERS];
  19.  
  20. RgnHandle cellrgns30[NUMPOWERS];
  21. int lastcellrgnx30[NUMPOWERS], lastcellrgny30[NUMPOWERS];
  22. RgnHandle gridcellrgns30[NUMPOWERS];
  23. int lastgridcellrgnx30[NUMPOWERS], lastgridcellrgny30[NUMPOWERS];
  24.  
  25. RgnHandle cellrgns15[NUMPOWERS];
  26. int lastcellrgnx15[NUMPOWERS], lastcellrgny15[NUMPOWERS];
  27. RgnHandle gridcellrgns15[NUMPOWERS];
  28. int lastgridcellrgnx15[NUMPOWERS], lastgridcellrgny15[NUMPOWERS];
  29.  
  30. int numwindsicns = 0;
  31.  
  32. Handle windsicnhandle[5];
  33.  
  34. static Image **best_terrain_images = NULL;
  35.  
  36. static Image **best_unseen_images = NULL;
  37.  
  38. /* Draw an image of the given type of unit in the given rectangle, possibly adding
  39.    an emblem if requested. */
  40.  
  41. void
  42. draw_unit_image(WindowPtr win, int sx, int sy, int sw, int sh, int u, int e, int mod)
  43. {
  44.     int ex, ey, ew, eh;
  45.     Rect srcrect, imagerect;
  46.     BitMap bm, *winbits;
  47.     Image *uimg;
  48.     MacImage *macuimg;
  49.  
  50.     /* Filter out very small images. */
  51.     if (sw <= 1)
  52.       return;
  53.     imagerect.top = sy;  imagerect.left = sx;
  54.     imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
  55.     if (sw <= 4) {
  56.         /* (should draw in a distinctive color if one is available) */
  57.         FillRect(&imagerect, QDPat(black));
  58.         return;
  59.     }
  60.     uimg = best_image(uimages[u], sw, sh);
  61.     /* There should always be *some* image to display. */
  62.     if (uimg && uimg->hook) {
  63.         macuimg = (MacImage *) uimg->hook;
  64.         winbits = &(((GrafPtr) win)->portBits);
  65.         if (macuimg->monopict != nil) {
  66.             DrawPicture(macuimg->monopict, &imagerect);
  67.         } else if (macuimg->colricon != nil
  68.                    && (minscreendepth > 1
  69.                           || (macuimg->monoicon == nil && macuimg->monosicn == nil))) {
  70.             PlotCIcon(&imagerect, (CIconHandle) macuimg->colricon);
  71.         } else if (macuimg->monoicon != nil) {
  72.             SetRect(&srcrect, 0, 0, 32, 32);
  73.             bm.rowBytes = 4;
  74.             bm.bounds = srcrect;
  75.             if (macuimg->maskicon != nil) {
  76.                 bm.baseAddr = *(macuimg->maskicon);
  77.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  78.             } else {
  79.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  80.                 FillRect(&imagerect, QDPat(white));
  81.             }
  82.             bm.baseAddr = *(macuimg->monoicon);
  83.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  84.         } else if (macuimg->monosicn != nil) {
  85.             SetRect(&srcrect, 0, 0, 16, 16);
  86.             if (sw > 64) {
  87.                 InsetRect(&imagerect, sw / 4, sh / 4);
  88.             }
  89.             bm.rowBytes = 2;
  90.             bm.bounds = srcrect;
  91.             if (macuimg->masksicn != nil) {
  92.                 bm.baseAddr = *(macuimg->masksicn);
  93.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  94.             } else {
  95.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  96.                 FillRect(&imagerect, QDPat(white));
  97.             }
  98.             bm.baseAddr = *(macuimg->monosicn);
  99.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  100.         } else {
  101.             run_warning("Unit image with no content?");
  102.         }
  103.     } else {
  104.         /* Rather a crummy substitute. */
  105.         FillRect(&imagerect, QDPat(black));
  106.     }
  107.     if (mod != 0) {
  108.         gray_out_rect(&imagerect);
  109.     }
  110.     /* Now draw a side emblem if asked for. */
  111.     if (between(0, e, numsides)) {
  112.         if (uimg &&
  113.             uimg->embedname &&
  114.             side_n(e) &&
  115.             side_n(e)->emblemname &&
  116.             strcmp(uimg->embedname, side_n(e)->emblemname) == 0) {
  117.             /* Correct emblem is part of the unit's image, don't need to draw. */
  118.         } else {
  119.             /* Get the size of the emblem, either from the image or by computing
  120.                a reasonable default. */
  121.             if (uimg && uimg->embedw > 0 && uimg->embedh > 0) {
  122.                 ew = uimg->embedw;  eh = uimg->embedh;
  123.             } else {
  124.                 ew = min(sw, max(8, sw / 4));  eh = min(sh, max(8, sh / 4));
  125.             }
  126.             /* Position the emblem, either explicitly, or default to UR corner
  127.                (note that we need the emblem's width to do this) */
  128.             if (uimg && uimg->embedx >= 0 && uimg->embedy >= 0) {
  129.                 ex = uimg->embedx;  ey = uimg->embedy;
  130.             } else {
  131.                 ex = sw - ew;  ey = 0;
  132.             }
  133.             /* Do the drawing proper. */
  134.             draw_side_emblem(win, sx + ex, sy + ey, ew, eh, e, plain_emblem);
  135.         }
  136.     }
  137. }
  138.  
  139. /* Draw a given side id's emblem. Uses the current GrafPort. */
  140.  
  141. void
  142. draw_side_emblem(WindowPtr win, int ex, int ey, int ew, int eh, int e, int style)
  143. {
  144.     int actualw, actualh;
  145.     Rect srcrect, imagerect, shadowrect;
  146.     BitMap bm, *winbits;
  147.     CIconHandle cicnhandle;
  148.     Image *eimg;
  149.     MacImage *maceimg;
  150.  
  151.     /* Filter out very small images. */
  152.     if (ew <= 1)
  153.       return;
  154.     if (ew <= 2) {
  155.         /* (should draw in a distinctive color if one is available) */
  156.         /* FillRect(&imagerect, QDPat(black)); */
  157.         return;
  158.     }
  159.     eimg = best_image(eimages[e], ew, eh);
  160.     imagerect.top = ey;  imagerect.left = ex;
  161.     actualw = eimg->w;  actualh = eimg->h;
  162.     if (ew >= actualw * 2 && eh >= actualh * 2) {
  163.         actualw *= 2;  actualh *= 2;
  164.     }
  165.     if (ew >= actualw * 2 && eh >= actualh * 2) {
  166.         actualw *= 2;  actualh *= 2;
  167.     }
  168.     if (actualw < ew)
  169.       ew = actualw;
  170.     if (actualh < eh)
  171.       eh = actualh;
  172.     imagerect.bottom = imagerect.top + eh;  imagerect.right = imagerect.left + ew;
  173.     /* If an image is available, display it, otherwise do nothing. */
  174.     if (eimg && eimg->hook) {
  175.         maceimg = (MacImage *) eimg->hook;
  176.         winbits = &(((GrafPtr) win)->portBits);
  177.         if (maceimg->monopict != nil) {
  178.             /* (should use a mask and shadow here somehow) */
  179.             DrawPicture(maceimg->monopict, &imagerect);
  180.         } else if (maceimg->colricon != nil
  181.                    && (minscreendepth > 1
  182.                           || (maceimg->monoicon == nil && maceimg->monosicn == nil))) {
  183.             cicnhandle = (CIconHandle) maceimg->colricon;
  184.             if (style == shadow_emblem) {
  185.                 SetRect(&srcrect, 0, 0, eimg->w, eimg->h);
  186.                 shadowrect = imagerect;
  187.                 OffsetRect(&shadowrect, (ew < 16 ? 1 : 2), (ew < 16 ? 1 : 2));
  188.                 bm.rowBytes = (*cicnhandle)->iconBMap.rowBytes;
  189.                 bm.bounds = srcrect;
  190.                 if (bm.rowBytes > 0) {
  191.                     bm.baseAddr = (char *) (*cicnhandle)->iconMaskData;
  192.                 }
  193.                 if (hasColorQD) {
  194.                     RGBColor tmpcolor;
  195.  
  196.                     tmpcolor.red = tmpcolor.green = tmpcolor.blue = 49000;
  197.                     RGBForeColor(&tmpcolor);
  198.                     if (bm.rowBytes > 0) {
  199.                         CopyBits(&bm, winbits, &srcrect, &shadowrect, srcCopy, nil);
  200.                     } else {
  201.                         PaintRect(&shadowrect);
  202.                     }
  203.                     /* Restore the previous color. */
  204.                     tmpcolor.red = tmpcolor.green = tmpcolor.blue = 0;
  205.                     RGBForeColor(&tmpcolor);
  206.                 } else {
  207.                     FillRect(&shadowrect, QDPat(gray));
  208.                 }
  209.             }
  210.             PlotCIcon(&imagerect, cicnhandle);
  211.         } else if (maceimg->monoicon != nil) {
  212.             SetRect(&srcrect, 0, 0, 32, 32);
  213.             bm.rowBytes = 4;
  214.             bm.bounds = srcrect;
  215.             if (maceimg->maskicon != nil) {
  216.                 bm.baseAddr = *(maceimg->maskicon);
  217.                 if (style == shadow_emblem) {
  218.                 }
  219.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  220.             } else {
  221.                 /* Use emblem bbox as default mask. */
  222.                 if (style == shadow_emblem) {
  223.                 }
  224.                 FillRect(&imagerect, QDPat(white));
  225.             }
  226.             bm.baseAddr = *(maceimg->monoicon);
  227.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  228.         } else if (maceimg->monosicn != nil) {
  229.             SetRect(&srcrect, 0, 0, 16, 16);
  230.             bm.rowBytes = 2;
  231.             bm.bounds = srcrect;
  232.             if (maceimg->masksicn != nil) {
  233.                 bm.baseAddr = *(maceimg->masksicn);
  234.                 if (style == shadow_emblem) {
  235.                 }
  236.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  237.             } else {
  238.                 /* Use emblem bbox as default mask. */
  239.                 if (style == shadow_emblem) {
  240.                 }
  241.                 FillRect(&imagerect, QDPat(white));
  242.             }
  243.             bm.baseAddr = *(maceimg->monosicn);
  244.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  245.         } else {
  246.             run_warning("Emblem image with no content?");
  247.         }
  248.     }
  249. }
  250.  
  251. void
  252. calc_best_terrain_images()
  253. {
  254.     int p, t;
  255.     Image *timg;
  256.  
  257.     best_terrain_images = (Image **) xmalloc(NUMPOWERS * numttypes * sizeof(Image *));
  258.     for_all_terrain_types(t) {
  259.         for (p = 0; p < NUMPOWERS; ++p) {
  260.             timg = best_image(timages[t], hws[p], hcs[p]);
  261.             best_terrain_images[p * numttypes + t] = timg;
  262.         }
  263.     }
  264.     best_unseen_images = (Image **) xmalloc(NUMPOWERS * sizeof(Image *));
  265.     if (unseen_image != NULL) {
  266.         for (p = 0; p < NUMPOWERS; ++p) {
  267.             timg = best_image(unseen_image, hws[p], hcs[p]);
  268.             best_unseen_images[p] = timg;
  269.         }
  270.     }
  271. }
  272.  
  273. void
  274. draw_cell_block(int sx, int sy, int n, int power, int t, int t2, int angle)
  275. {
  276.     Rect rect;
  277.     Image *timg;
  278.     MacImage *mactimg;
  279.     RGBColor cellcolor, oldcolor;                
  280.  
  281.     rect.left = sx;  rect.top = sy;
  282.     rect.right = rect.left + n * hws[power];  rect.bottom = rect.top + hcs[power];
  283.     if (angle == 30) {
  284.         rect.bottom = rect.top + hcs[power] / 2;
  285.     } else if (angle == 15) {
  286.         rect.bottom = rect.top + hcs[power] / 4;
  287.     }
  288.     if (best_terrain_images == NULL)
  289.       calc_best_terrain_images();
  290.     if (t == NONTTYPE)
  291.       timg = best_unseen_images[power];
  292.     else
  293.       timg = best_terrain_images[power * numttypes + t];
  294.     if (timg && timg->hook) {
  295.         mactimg = (MacImage *) timg->hook;
  296.         if (hasColorQD) {
  297.             if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
  298.                 FillCRect(&rect, mactimg->colrpat);
  299.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  300.                 /* A solid color is preferable to a b/w pattern. */
  301.                 cellcolor.red   = (tcolors[t]->r) << 8;
  302.                 cellcolor.green = (tcolors[t]->g) << 8;
  303.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  304.                 RGBForeColor(&cellcolor);
  305.                 PaintRect(&rect);
  306.                 /* Restore the previous color. */
  307.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  308.                 RGBForeColor(&oldcolor);
  309.             } else if (mactimg->patdefined) {
  310.                 FillRect(&rect, (unsigned char *) &(mactimg->monopat));
  311.             }
  312.         } else {
  313.             FillRect(&rect, (unsigned char *) &(mactimg->monopat));
  314.         }
  315.     } else {
  316.         /* No image; use a color instead. */
  317.         if (hasColorQD) {
  318.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  319.                 cellcolor.red   = (tcolors[t]->r) << 8;
  320.                 cellcolor.green = (tcolors[t]->g) << 8;
  321.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  322.                 RGBForeColor(&cellcolor);
  323.                 PaintRect(&rect);
  324.                 /* Restore the previous color. */
  325.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  326.                 RGBForeColor(&oldcolor);
  327.             } else {
  328.                 /* leave it blank? sigh */
  329.             }
  330.         } else {
  331.             /* leave it blank? sigh */
  332.         }
  333.     }
  334.     /* If any graying/shading was requested, do it. */
  335.     if (t2 < 0) {
  336.         if (t2 == -1) {
  337.             PenPat(QDPat(ltGray));
  338.             PenMode(patOr);
  339.         } else if (t2 == -2) {
  340.             PenPat(QDPat(gray));
  341. /*                PenMode(patBic);  */
  342.             PenMode(notPatOr);
  343.         }
  344.         PaintRect(&rect);
  345.         PenNormal();
  346.     }
  347. }
  348.  
  349. /* Draw the given terrain type into a hexagonal region of the given size and position. */
  350.  
  351. void
  352. draw_hex_region(int sx, int sy, int power, int dogrid, int t, int t2, int angle)
  353. {
  354.     Image *timg;
  355.     MacImage *mactimg;
  356.     RGBColor hexcolor, oldcolor;
  357.     RgnHandle rgn;
  358.  
  359.     if (best_terrain_images == NULL)
  360.       calc_best_terrain_images();
  361.     if (cellrgns[power] == nil)
  362.       make_cell_clip(power);
  363.     if (angle == 30) {
  364.           OffsetRgn(cellrgns30[power], sx - lastcellrgnx30[power], sy - lastcellrgny30[power]);
  365.           lastcellrgnx30[power] = sx;  lastcellrgny30[power] = sy;
  366.           OffsetRgn(gridcellrgns30[power], sx - lastgridcellrgnx30[power], sy - lastgridcellrgny30[power]);
  367.           lastgridcellrgnx30[power] = sx;  lastgridcellrgny30[power] = sy;
  368.         rgn = (dogrid ? gridcellrgns30[power] : cellrgns30[power]);
  369.     } else if (angle == 15) {
  370.           OffsetRgn(cellrgns15[power], sx - lastcellrgnx15[power], sy - lastcellrgny15[power]);
  371.          lastcellrgnx15[power] = sx;  lastcellrgny15[power] = sy;
  372.           OffsetRgn(gridcellrgns15[power], sx - lastgridcellrgnx15[power], sy - lastgridcellrgny15[power]);
  373.           lastgridcellrgnx15[power] = sx;  lastgridcellrgny15[power] = sy;
  374.         rgn = (dogrid ? gridcellrgns15[power] : cellrgns15[power]);
  375.     } else {
  376.           OffsetRgn(cellrgns[power], sx - lastcellrgnx[power], sy - lastcellrgny[power]);
  377.           lastcellrgnx[power] = sx;  lastcellrgny[power] = sy;
  378.           OffsetRgn(gridcellrgns[power], sx - lastgridcellrgnx[power], sy - lastgridcellrgny[power]);
  379.          lastgridcellrgnx[power] = sx;  lastgridcellrgny[power] = sy;
  380.         rgn = (dogrid ? gridcellrgns[power] : cellrgns[power]);
  381.     }
  382.     if (t == NONTTYPE)
  383.       timg = best_unseen_images[power];
  384.     else
  385.       timg = best_terrain_images[power * numttypes + t];
  386.     if (timg && timg->hook) {
  387.         mactimg = (MacImage *) timg->hook;
  388.         if (hasColorQD) {
  389.             if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
  390.                 FillCRgn(rgn, mactimg->colrpat);
  391.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  392.                 /* A solid color is preferable to a b/w pattern. */
  393.                 hexcolor.red   = (tcolors[t]->r) << 8;
  394.                 hexcolor.green = (tcolors[t]->g) << 8;
  395.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  396.                 RGBForeColor(&hexcolor);
  397.                 PaintRgn(rgn);
  398.                 /* Restore the previous color. */
  399.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  400.                 RGBForeColor(&oldcolor);
  401.             } else if (mactimg->patdefined) {
  402.                 /* Fall back on the b/w pattern. */
  403.                 FillRgn(rgn, (unsigned char *) &(mactimg->monopat));
  404.             }
  405.         } else {
  406.             FillRgn(rgn, (unsigned char *) &(mactimg->monopat));
  407.         }
  408.     } else {
  409.         if (hasColorQD) {
  410.             if (tcolors[t] != NULL && tcolors[t]->defined && maxscreendepth > 1) {
  411.                 /* Use the solid color. */
  412.                 hexcolor.red   = (tcolors[t]->r) << 8;
  413.                 hexcolor.green = (tcolors[t]->g) << 8;
  414.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  415.                 RGBForeColor(&hexcolor);
  416.                 PaintRgn(rgn);
  417.                 /* Restore the previous color. */
  418.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  419.                 RGBForeColor(&oldcolor);
  420.             } else {
  421.             }
  422.         } else {
  423.         }
  424.     }
  425.     /* Maybe overlay the cell. */
  426.     if (t2 < 0) {
  427.         if (t2 == -1) {
  428.             PenPat(QDPat(ltGray));
  429.             PenMode(patOr);
  430.         } else if (t2 == -2) {
  431.             PenPat(QDPat(gray));
  432. /*                PenMode(patBic);  */
  433.             PenMode(notPatOr);
  434.         }
  435.         PaintRgn(rgn);
  436.         PenNormal();
  437.     }
  438. }
  439.  
  440. /* Draw a set of borders for the given position. */
  441.  
  442. void
  443. draw_border_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle)
  444. {
  445.     int wid = bwid[power], wid2, dir, tweakedcolor = FALSE;
  446.     int sx1, sy1, sx2, sy2;
  447.     Image *timg;
  448.     MacImage *mactimg;
  449.     RGBColor cellcolor, oldcolor;                
  450.  
  451.     if (wid == 0)
  452.       return;
  453.     wid2 = wid / 2;
  454.     if (0 /* power == 4*/) {
  455.         Rect srcrect, destrect;
  456.         BitMap *winbits;
  457.  
  458.         winbits = &(((GrafPtr) win)->portBits);
  459.         SetRect(&srcrect, 0, 0, 32, 32);
  460.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  461.         CopyBits(&(bordbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  462.         return;
  463.     }
  464.     PenSize(wid, wid);
  465.     /* Decide on the line color/pattern to use. */
  466.     timg = best_image(timages[t], wid, wid);
  467.     if (timg && timg->hook) {
  468.         mactimg = (MacImage *) timg->hook;
  469.         if (hasColorQD) {
  470.             if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
  471.                 PenPixPat(mactimg->colrpat);
  472.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  473.                 /* A solid color is preferable to a b/w pattern. */
  474.                 cellcolor.red   = (tcolors[t]->r) << 8;
  475.                 cellcolor.green = (tcolors[t]->g) << 8;
  476.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  477.                 RGBForeColor(&cellcolor);
  478.                 tweakedcolor = TRUE;
  479.             } else {
  480.                 PenPat((unsigned char *) &(mactimg->monopat));
  481.             }
  482.         } else {
  483.             PenPat((unsigned char *) &(mactimg->monopat));
  484.         }
  485.     } else {
  486.         if (hasColorQD) {
  487.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  488.                 /* A solid color is preferable to gray. */
  489.                 cellcolor.red   = (tcolors[t]->r) << 8;
  490.                 cellcolor.green = (tcolors[t]->g) << 8;
  491.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  492.                 RGBForeColor(&cellcolor);
  493.                 tweakedcolor = TRUE;
  494.             } else {
  495.                 PenPat(QDPat(dkGray));
  496.             }
  497.         } else {
  498.             PenPat(QDPat(dkGray));
  499.         }
  500.     }
  501.     for_all_directions(dir) {
  502.         if (bitmask & (1 << dir)) {
  503.             /* Actually draw the line. */
  504.             sx1 = bsx[power][dir];  sy1 = bsy[power][dir];
  505.             if (angle == 30) {
  506.                 sy1 /= 2;
  507.             } else if (angle == 15) {
  508.                 sy1 /= 4;
  509.             }
  510.             MoveTo(sx + sx1 - wid2, sy + sy1 - wid2);
  511.             sx2 = bsx[power][dir+1];  sy2 = bsy[power][dir+1];
  512.             if (angle == 30) {
  513.                 sy2 /= 2;
  514.             } else if (angle == 15) {
  515.                 sy2 /= 4;
  516.             }
  517.             LineTo(sx + sx2 - wid2, sy + sy2 - wid2);
  518.         }
  519.     }
  520.     PenNormal();
  521.     if (tweakedcolor) {
  522.         /* Restore the previous color. */
  523.         oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  524.         RGBForeColor(&oldcolor);
  525.     }
  526. }
  527.  
  528. /* Draw a set of connections for the given ttype and given cell. */
  529.  
  530. void
  531. draw_connection_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle)
  532. {
  533.     int dir, wid = cwid[power], ly, tweakedcolor = FALSE;
  534.     Image *timg;
  535.     MacImage *mactimg;
  536.     RGBColor cellcolor, oldcolor;                
  537.  
  538.     if (wid == 0)
  539.       return;
  540.     if (0 /*power == 4*/) {
  541.         Rect srcrect, destrect;
  542.         BitMap *winbits;
  543.  
  544.         winbits = &(((GrafPtr) win)->portBits);
  545.         SetRect(&srcrect, 0, 0, 32, 32);
  546.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  547.         CopyBits(&(connbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  548.         return;
  549.     }
  550.     PenSize(wid, wid);
  551.     timg = best_image(timages[t], wid, wid);
  552.     if (timg && timg->hook) {
  553.         mactimg = (MacImage *) timg->hook;
  554.         if (hasColorQD) {
  555.             if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
  556.                 PenPixPat(mactimg->colrpat);
  557.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  558.                 /* A solid color is preferable to a b/w pattern. */
  559.                 cellcolor.red   = (tcolors[t]->r) << 8;
  560.                 cellcolor.green = (tcolors[t]->g) << 8;
  561.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  562.                 RGBForeColor(&cellcolor);
  563.                 tweakedcolor = TRUE;
  564.             } else {
  565.                 PenPat((unsigned char *) &(mactimg->monopat));
  566.             }
  567.         } else {
  568.             PenPat((unsigned char *) &(mactimg->monopat));
  569.         }
  570.     } else {
  571.         if (hasColorQD) {
  572.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  573.                 /* A solid color is preferable to gray. */
  574.                 cellcolor.red   = (tcolors[t]->r) << 8;
  575.                 cellcolor.green = (tcolors[t]->g) << 8;
  576.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  577.                 RGBForeColor(&cellcolor);
  578.                 tweakedcolor = TRUE;
  579.             } else {
  580.                 PenPat(QDPat(gray));
  581.             }
  582.         } else {
  583.             PenPat(QDPat(gray));
  584.         }
  585.     }
  586.     for_all_directions(dir) {
  587.         if (bitmask & (1 << dir)) {
  588.             MoveTo(sx + hws[power] / 2 - wid / 2, sy + hhs[power] / (angle == 30 ? 4 : 2) - wid / 2);
  589.             ly = lsy[power][dir];
  590.             if (angle == 30)
  591.               ly /= 2;
  592.             else if (angle == 15)
  593.               ly /= 4;
  594.             Line(lsx[power][dir], ly);
  595.         }
  596.     }
  597.     PenNormal();
  598.     if (tweakedcolor) {
  599.         /* Restore the previous color. */
  600.         oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  601.         RGBForeColor(&oldcolor);
  602.     }
  603. }
  604.  
  605. /* This draws a type of terrain in a way that indicates its subtype. */
  606.  
  607. void
  608. draw_terrain_sample(Rect tmprect, int t)
  609. {
  610.     switch (t_subtype(t)) {
  611.         case cellsubtype:
  612.             draw_hex_region(tmprect.left, tmprect.top, 4, FALSE, t, 0, 90);
  613.             break;
  614.         case bordersubtype:
  615.             draw_border_line_multiple(designwin, tmprect.left, tmprect.top, -1, 4, t, 90);
  616.             break;
  617.         case connectionsubtype:
  618.             draw_connection_line_multiple(designwin, tmprect.left, tmprect.top, -1, 4, t, 90);
  619.             break;
  620.         case coatingsubtype:
  621.             draw_hex_region(tmprect.left, tmprect.top, 4, FALSE, t, 0, 90);
  622.             /* Make it a 50% pattern. (should make more obvious somehow?) */
  623.             gray_out_rect(&tmprect);
  624.             break;
  625.         default:
  626.             terrain_subtype_warning("draw sample", t);
  627.             break;
  628.     }
  629. }
  630.  
  631. /* Draw a set of country border at the given position. */
  632.  
  633. void
  634. draw_country_borders(WindowPtr win, int sx, int sy, int bitmask, int power, int shade, int angle)
  635. {
  636.     int wid = bwid2[power], wid2, dir, dx1, dy1;
  637.  
  638.     if (wid == 0) return;
  639.     PenSize(wid, wid);
  640.     if (shade == 0) PenPat(QDPat(black));
  641.     if (shade == 2) PenPat(QDPat(gray));
  642.     wid2 = wid / 2;
  643.     for_all_directions(dir) {
  644.         if (bitmask & (1 << dir)) {
  645.             dx1 = bsx[power][dir];  dy1 = bsy[power][dir];
  646.             if (angle == 30) { dy1 /= 2; }
  647.             if (angle == 15) { dy1 /= 4; }
  648.             MoveTo(sx + dx1 - wid2, sy + dy1 - wid2);
  649.             dx1 = bsx[power][dir+1];  dy1 = bsy[power][dir+1];
  650.             if (angle == 30) { dy1 /= 2; }
  651.             if (angle == 15) { dy1 /= 4; }
  652.             LineTo(sx + dx1 - wid2, sy + dy1 - wid2);
  653.         }
  654.     }
  655.     PenNormal();
  656. }
  657.  
  658. /* Draw a set of theater borders at the given position. */
  659.  
  660. void
  661. draw_theater_borders(WindowPtr win, int sx, int sy, int bitmask, int power)
  662. {
  663.     int wid, wid2, dir;
  664.     Rect tmprect;
  665.  
  666.     if (bwid[power] > 0) {
  667.         wid = 2;
  668.         wid2 = 1;
  669.         PenSize(wid, wid);
  670.         for_all_directions(dir) {
  671.             if (bitmask & (1 << dir)) {
  672.                 MoveTo(sx + bsx[power][dir] - wid2 + 1, sy + bsy[power][dir] - wid2 + 1);
  673.                 LineTo(sx + bsx[power][dir+1] - wid2 + 1, sy + bsy[power][dir+1] - wid2 + 1);
  674.             }
  675.         }
  676.         PenMode(notPatCopy);
  677.         for_all_directions(dir) {
  678.             if (bitmask & (1 << dir)) {
  679.                 MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
  680.                 LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
  681.             }
  682.         }
  683.         PenNormal();
  684.     } else {
  685.         SetRect(&tmprect, sx, sy, sx + hws[power], sy + hhs[power]);
  686.         OffsetRect(&tmprect, 1, 1);
  687.         FillRect(&tmprect, QDPat(black));
  688.         OffsetRect(&tmprect, -1, -1);
  689.         FillRect(&tmprect, QDPat(white));
  690.     }
  691. }
  692.  
  693. int
  694. draw_elevation_here(int x, int y)
  695. {
  696.     return terrain_visible(x, y);
  697. }
  698.  
  699. /* Indicate the elevation of the given location, textually for now. */
  700.  
  701. void
  702. draw_elevation(int sx, int sy, int power, int elev)
  703. {
  704.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  705.     if (elev != 0) {
  706.         sprintf(spbuf, "%d", elev);
  707.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  708.     }
  709.     /* (Also draw contour lines eventually) */
  710. }
  711.  
  712. /* Don't draw the temperature in every cell, only do ones with even coords or
  713.    ones where the temperature in any adjacent cell is different. */
  714.  
  715. int
  716. draw_temperature_here(int x, int y)
  717. {
  718.     int dir, x1, y1, temphere = temperature_at(x, y);
  719.  
  720.     if (dside->designer) return TRUE;
  721.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  722.     for_all_directions(dir) {
  723.         point_in_dir(x, y, dir, &x1, &y1);
  724.         if (temphere != temperature_at(x1, y1)) {
  725.             return TRUE;
  726.         }
  727.     }
  728.     return (x % 2 == 0 && y % 2 == 0);
  729. }
  730.  
  731. /* Indicate the temperature of the given location, textually for now. */
  732.  
  733. void
  734. draw_temperature(int sx, int sy, int power, int temp)
  735. {
  736.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  737.     if (1 /* temp != 0 */) {
  738.         sprintf(spbuf, "%d°", temp);  /* (should do char more portably) */
  739.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  740.     }
  741.     /* (Also draw isotherms eventually) */
  742. }
  743.  
  744. /* Don't draw the winds in every cell, only do ones with odd coords or
  745.    ones where the wind in any adjacent cell is different. */
  746. /* (generic routine?) */
  747.  
  748. int
  749. draw_winds_here(int x, int y)
  750. {
  751.     int dir, x1, y1, windhere = raw_wind_at(x, y);
  752.  
  753.     if (dside->designer) return TRUE;
  754.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  755.     for_all_directions(dir) {
  756.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  757.             if (windhere != raw_wind_at(x1, y1)) {
  758.                 return TRUE;
  759.             }
  760.         }
  761.     }
  762.     return (x % 2 == 1 && y % 2 == 1);
  763. }
  764.  
  765. /* Indicate the winds at the given location. */
  766.  
  767. void
  768. draw_winds(int sx, int sy, int power, int wdir, int wforce)
  769. {
  770.     int i;
  771.     GrafPtr curport;
  772.  
  773.     sx += (hws[power] - 16) / 2;  sy += (hhs[power] - 16) / 2;
  774.     if (wforce > 4) wforce = 4;
  775.     if (wforce == 0) wdir = 0;
  776.     /* Collect sicns if not already in. */
  777.     if (numwindsicns == 0) {
  778.         for (i = 0; i <= 4; ++i) {
  779.             windsicnhandle[i] = GetResource('SICN', sicnWinds0 + i);
  780.         }
  781.         numwindsicns = 5;
  782.     }
  783.     GetPort(&curport);
  784.     /* Draw an offset white version, for contrast. */
  785.     plot_sicn(curport, sx + 1, sy + 1, windsicnhandle[wforce], wdir, FALSE, srcBic);
  786.     plot_sicn(curport, sx, sy, windsicnhandle[wforce], wdir, FALSE, srcOr);
  787. }
  788.  
  789. int
  790. draw_clouds_here(int x, int y)
  791. {
  792.     if (dside->designer) return TRUE;
  793.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  794.     return TRUE;
  795. }
  796.  
  797. void
  798. draw_clouds(int sx, int sy, int power, int cloudtype)
  799. {
  800.     Rect tmprect;
  801.  
  802.     if (cloudtype == 0) return;
  803.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  804.     SetRect(&tmprect, sx - hws[power] / 2, sy - hhs[power] / 2, sx + hws[power] / 2, sy + hhs[power] / 2);
  805.     /* Should use pat# 130 patterns for this instead. */
  806.     PenPat(cloudtype == 3 ? QDPat(dkGray) : (cloudtype == 2 ? QDPat(gray) : QDPat(ltGray)));
  807.     PenMode(patBic);
  808.     PaintOval(&tmprect);
  809.     PenNormal();
  810. }
  811.  
  812. /* Draw the number of units observing a cell (for debugging). */
  813.  
  814. void
  815. draw_coverage(int sx, int sy, int power, int cov)
  816. {
  817.     /* Adjust to the lower left corner of the cell. */
  818.     sx += 2;  sy += hcs[power] - 2;
  819.     if (cov > 0) {
  820.         sprintf(spbuf, ":%d:", cov);
  821.     }
  822.     draw_legend_text(sx, sy, hhs[power] / 2, spbuf, -1);
  823. }
  824.  
  825. /* Draw a unit's name or number. */
  826.  
  827. void
  828. draw_unit_name(Unit *unit, int sx, int sy, int sw, int sh)
  829. {
  830.     char legend[BUFSIZE];
  831.  
  832.     name_or_number(unit, legend);
  833.     if (strlen(legend) > 0) {
  834.         draw_legend_text(sx + sw + 1, sy + sh/2, sh, legend, -1);
  835.     }
  836. }
  837.  
  838. void
  839. draw_legend_text(int sx, int sy, int sh, char *legend, int just)
  840. {
  841.     int strwid, strleft;
  842.     Rect maskrect;
  843.     FontInfo fontinfo;
  844.     
  845.     /* Scale text sizes to fit in smaller cells if necessary. */
  846.     TextSize(min(max(5, sh), 10));
  847.     strwid = TextWidth(legend, 0, strlen(legend));
  848.     if (just < 0) {
  849.         strleft = sx;
  850.     } else if (just > 0) {
  851.         strleft = sx - strwid;
  852.     } else {
  853.         strleft = sx - strwid / 2;
  854.     }
  855.     MoveTo(strleft, sy);
  856.     if (0) {
  857.         /* Make it readable against a noisy background. */
  858. /*        TextFace(bold|outline); */
  859.         TextMode(srcBic);
  860.     } else {
  861.         /* This makes a big white box for name, less attractive but easier to read. */
  862.         GetFontInfo(&fontinfo);
  863.         maskrect.top = sy - fontinfo.ascent;
  864.         /* Ensure a one pixel of white all along the top. */
  865.         maskrect.top += 1;
  866.         maskrect.left = strleft - 1;
  867.         maskrect.bottom = sy + fontinfo.descent;
  868.         /* Ensure a one pixel of white all along the bottom, even below descenders. */
  869.         maskrect.bottom += 1;
  870.         maskrect.right = maskrect.left + strwid + 1;
  871.         FillRect(&maskrect, QDPat(white));
  872.     }
  873.     DrawText(legend, 0, strlen(legend));
  874. }
  875.  
  876. void
  877. draw_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
  878. {
  879.     Rect tmprect;
  880.  
  881.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  882.     if (sw >= 16) {
  883.         /* Instead should save image under here, then draw blast */
  884.         InvertRect(&tmprect);
  885.     } else {
  886.         InvertRect(&tmprect);
  887.     }
  888. }
  889.  
  890. void
  891. clear_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
  892. {
  893.     Rect tmprect;
  894.  
  895.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  896.     if (sw >= 16) {
  897.         /* Instead should restore image under here */
  898.         InvertRect(&tmprect);
  899.     } else {
  900.         InvertRect(&tmprect);
  901.     }
  902. }
  903.  
  904. int
  905. picture_width(PicHandle pichandle)
  906. {
  907.     return ((*pichandle)->picFrame.right - (*pichandle)->picFrame.left);
  908. }
  909.  
  910. int
  911. picture_height(PicHandle pichandle)
  912. {
  913.     return ((*pichandle)->picFrame.bottom - (*pichandle)->picFrame.top);
  914. }
  915.  
  916. /* Generic sicn drawer. */
  917.  
  918. void
  919. plot_sicn(WindowPtr win, int sx, int sy, Handle sicnhandle, int n, int erase, int mode)
  920. {
  921.     Rect srcrect, imagerect;
  922.     BitMap bm, *winbits;
  923.  
  924.     if (sicnhandle == nil) return;
  925.     imagerect.left = sx;  imagerect.top = sy;
  926.     imagerect.right = imagerect.left + 16;  imagerect.bottom = imagerect.top + 16;
  927.     winbits = &(((GrafPtr) win)->portBits);
  928.     SetRect(&srcrect, 0, 0, 16, 16);
  929.     bm.rowBytes = 2;
  930.     bm.bounds = srcrect;
  931.     if (erase) EraseRect(&imagerect);
  932.     bm.baseAddr = *(sicnhandle) + 32 * n;
  933.     CopyBits(&bm, winbits, &srcrect, &imagerect, mode, nil);
  934. }
  935.  
  936. /* Given a rectangle, make half of its pixels white. */
  937.  
  938. void
  939. gray_out_rect(Rect *rectptr)
  940. {
  941.     PenPat(QDPat(gray));
  942.     PenMode(patBic);
  943.     PaintRect(rectptr);
  944.     PenNormal();
  945. }
  946.